<?php

namespace Modules\Production\Repository;


use App\Services\KingDeeService;
use App\Services\UnitService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Modules\Base\Repository\BoxNumberRepository;
use Modules\Base\Service\BoxService;
use Modules\Production\Models\ProductionOrderDetail;
use Modules\Production\Models\ProductionReportDetail;
use Modules\Production\Models\ProductionReportOrder;
use Modules\Production\Models\ReportOrderBox;
use SimpleSoftwareIO\QrCode\Facades\QrCode;
use App\Enums\BoxFrom;
use App\Enums\ProductionOrderBackStatus;

class ProductionReportOrderRepository
{

    /**
     * 保存汇报单信息
     * @param $postData
     */
    static public function storeBy($postData){

        if($postData['type'] == '2'){

            if(empty($postData['box_list'])){
                throw new \Exception('半成品汇报箱号信息不能为空');
            }

            if(count($postData['box_list']) != $postData['cases']){
                throw new \Exception('箱号个数必须与汇报箱号一致');
            }

            if($postData['qty'] != array_sum(array_column($postData['box_list'],'qty')) ){
                throw new \Exception('箱号明细数量总和必须与汇报数量一致');
            }

        }

        //生产工单表头信息
        $production = ProductionOrderRepository::getOrderById($postData['production_id']);

        if(StockTaskScanRepository::getCountByProductionId($production->id) <= 0){
            file_put_contents('report_error.txt',UnitService::getNowTime() . "::{$production->fbillno}::未领料\r\n",FILE_APPEND);
        }

        $processDetailId = '';

        try {

            DB::beginTransaction();

            if(!empty($production->flow_code)){

                //工单总工时
                $productionTotalHours = ProcessDetailRepository::getTotalHoursByProductionId($production->id);
                if($productionTotalHours <= 0){
                    throw new \Exception('当前工单工序未汇报');
                }

                //工序报工汇总
                $process = self::getTotalHours($production->id,true);
                $processDetailId = implode(',',$process['detailId']);
                $people     = $process['peopleSum'];
                $hours      = $process['totalHhours'] == 0 ? 0 : round($process['totalHhours'] / $process['peopleSum'],2);
                $totalHours = $process['totalHhours'];
            }else{

                //没有绑定工艺流程，工时手动输入

                $people     = $postData['people'];
                $hours      = $postData['work_hours'];
                $totalHours = $postData['people'] * $postData['work_hours'];
            }

            $reportNo = UnitService::createDocno('SCHB');

            $order = [
                'org_code'      => $production->fprdorgid_number,
                'cargo_type'    => $production->fownertypeidsety,
                'cargo_code'    => $production->fowneridsety_number,
                'docno'         => $reportNo,
                'production_id' => $production->id,
                'production_no' => $production->fbillno,
                'type'          => $postData['type'],
                'kingdee_status'=> 1,
            ];

            //生产汇报单表头入库
            $orderId = (new ProductionReportOrder())->storeBy($order);

            $detail = [
                'order_id'      => $orderId,
                'material_no'   => $production->fmaterialid,
                'material_name' => $production->fmaterialname,
                'qty'           => $postData['qty'],
                'cases'         => $postData['cases'],
                'people'        => $people,
                'work_hours'    => $hours,
                'total_hours'   => $totalHours,
                'process_detail'=> $processDetailId,
            ];

            (new ProductionReportDetail())->storeBy($detail);

            $reportOrderBox = [];
            if($postData['type'] == '2'){
                $reportOrderBox = self::makeBoxBySemiFinished($detail,$postData['box_list']);
            }else{
                //生产箱号二维码
                $boxList = BoxService::makeBoxNumber(
                    $postData['cases'],
                    BoxFrom::REPORT_ORDER->value,
                    $orderId,
                    $production->fprdorgid_number,
                    $reportNo,
                    $production->fmaterialid,
                    true
                );
                /*foreach ($boxList as &$boxVal){
                    $boxVal['img'] = env('APP_URL') . $boxVal['img'];
                }*/
                $reportOrderBox = self::makeBoxByFinished($detail,$boxList);
            }

            //汇报箱号添加
            ReportOrderBox::insert($reportOrderBox);

            //累加汇报数量到工单
            ProductionOrderRepository::increment($production->id,'report_qty',$postData['qty']);

            //推送金蝶
            self::pushKingDee($production,$order,$detail,$postData['time']);

            DB::commit();
            return [
                'report_no' => $reportNo,
                'date'      => date('Y-m-d'),
                'box'       => $reportOrderBox
            ];
        }catch (\Exception $e){
            DB::rollBack();

            if(mb_strpos($e->getMessage(),'业务状态不为 开工或完工，生产汇报单保存不成功') !== false){
                file_put_contents('report_error.txt',UnitService::getNowTime() . "::{$production->fbillno}::业务状态不为 开工或完工，生产汇报单保存不成功\r\n",FILE_APPEND);
            }

            throw $e;
        }

    }

    /**
     * 总工时人数计算
     * @param $productionId
     * @return mixed
     */
    static public function getTotalHours($productionId,$setReport = false){

        $process = ProcessDetailRepository::getProcessExtendDetailByProductionId($productionId,0);

        $peopleSum = 0;
        $totalHhours = 0;
        $detailIds = [];
        foreach($process as $processItem){
            foreach ($processItem->detail as $detailItem){
                $peopleSum += $detailItem->people;
                $totalHhours += $detailItem->total_hours;
                $detailIds[] = $detailItem->id;
            }
        }

        //设为已汇报
        if($setReport){
            ProcessDetailRepository::updateProcessDetailToReport($detailIds);
        }

        return [
            'peopleSum'     => $peopleSum,
            'totalHhours'   => $totalHhours,
            'detailId'      => $detailIds
        ];

    }

    /**
     * 半成品箱号
     * @param $reportOrderDetail
     * @param $boxList
     * @return array
     */
    static public function makeBoxBySemiFinished($reportOrderDetail,$boxList){

        $box = [];
        foreach ($boxList as $val){
            $box[] = [
                'report_order_id'   => $reportOrderDetail['order_id'],
                'lot_num'           => $val['box_num'],
                'qty'               => $val['qty'],
                'material_no'       => $reportOrderDetail['material_no'],
                'creator_id'        => Auth::guard(getGuardName())->id(),
                'created_at'        => time(),
            ];
        }
        return $box;
    }

    /**
     * 成品箱号
     * @param $reportOrderDetail
     * @param $boxList
     * @return array
     */
    static public function makeBoxByFinished($reportOrderDetail,$boxList){
        $box = [];
        foreach ($boxList as $val){
            $box[] = [
                'report_order_id'   => $reportOrderDetail['order_id'],
                'lot_num'           => $val['code'],
                'qty'               => 0,
                'material_no'       => $reportOrderDetail['material_no'],
                'creator_id'        => Auth::guard(getGuardName())->id(),
                'created_at'        => time(),
            ];
        }
        return $box;
    }

    /**
     * 生产汇报单推送金蝶
     * @param $order
     */
    static public function pushKingDee($production,$reportOrder,$detail,$time = null){
        $order = [
            'FBILLTYPEID'   => 'PRD_MORPT',
            'FBILLNO'       => $reportOrder['docno'],
            'FORGID'        => $reportOrder['org_code'],
            'FDATE'         => $time ?: date('Y-m-d H:i:s'),

        ];
        $order['FEntity'] = [
            [
                'FOwnerTypeId'          => $reportOrder['cargo_type'],
                'FOwnerId'              => $reportOrder['cargo_code'],
                'FSRCBILLNO'            => $production->fmobillno,
                'FSRCSEQ'               => $production->fmoentryseq,
                'FMATERIALID'           => $production->fmaterialid,
                'FUNITID'               => $production->funitid_number,
                'FQTY'                  => $detail['qty'],
                'FGIVEAWAY'             => 'false',
                'FHUMANQTY'             => $detail['people'],
                'FPERSONNELUNITTIME'    => $detail['work_hours'],
                'FHRWORKTIME'           => $detail['total_hours'],
                'FPLANNEDSTARTTIME'     => date('Y-m-d H:i:s'),
                'FPLANNEDCOMPLETIONTIME'=> date('Y-m-d H:i:s'),
                'FNOTE' => '',
            ]
        ];
        return (new KingDeeService())->form('TVJB_DJWMSDJ')->invokeSave($order);
    }

    /**
     * 根据id查询生产汇报单及明细
     * @param $reportId
     * @return mixed
     */
    static public function getReportOrderAndDetailById($reportId){
        return ProductionReportOrder::where('id',$reportId)->with('detail')->first();
    }

    /**
     * 根据箱号查询生产汇报单
     * @param $lotnum
     */
    static public function getReportOrderByLotnum($lotnum){

        //$boxInfo = BoxNumberRepository::getReportOrderBoxByCode($lotnum);
        //$boxInfo = ReportOrderBoxRepository::getByLotNum($lotnum);
        $boxInfo = ReportOrderBoxRepository::getByLotNumList($lotnum);
        if($boxInfo->isEmpty()){
            throw new \Exception('箱号不存在');
        }

        $reportList = [];
        $reportOrder = [];
        foreach ($boxInfo as $item){
            //汇报单数据
            $reportOrder = self::getReportOrderAndDetailById($item->report_order_id);
            if(!$reportOrder){
                continue;
            }
            $reportOrder = $reportOrder->toArray();
            $reportOrder['detail'] = $reportOrder['detail'][0];

            if($reportOrder['detail']['inbound_qty'] >= $reportOrder['detail']['qty']){
                continue;
            }

            $reportOrder['box'] = $item;

            $reportList[] = $reportOrder;
        }

        return $reportList;

    }

    /**
     * 根据子项id查询子项信息并且返回单据头
     * @param $detailId
     */
    static public function getReportDetailAndOrderById($detailId){
        return ProductionReportDetail::where('id',$detailId)->with('order')->first();
    }

    /**
     * 检查工单号是否允许汇报
     * @param $productionNo
     */
    static public function checkProductionOrder($productionNo){

        $production = ProductionOrderRepository::getIdByDocno($productionNo);
        if(!$production){
            throw new \Exception('工单号不存在');
        }

        $production = $production->toArray();

        //判断是否未领料
        //if(StockTaskScanRepository::getCountByProductionId($production['id']) <= 0){
        if(ProductionOrderDetailRepository::getPickQty($production['id']) <= 0){
            throw new \Exception('当前工单未领料');
        }

        $productionTotalHours = 0;
        if(!empty($production['flow_code'])){
            //工单总工时
            $productionTotalHours = ProcessDetailRepository::getTotalHoursByProductionId($production['id']);
            if($productionTotalHours <= 0){
                throw new \Exception('当前工单工序未汇报');
            }

            //工单总工时
            $production['total_hours'] = $productionTotalHours;

            $totalProcess = self::getTotalHours($production['id'],false);
            //document.getElementById
            $lastProcess = ProcessDetailRepository::getLastProcess($production['id']);

            //print_r($lastProcess->toArray());exit();
            //当前总工时
            $production['now_people']       = $totalProcess['peopleSum'];
            $production['now_hours']        = $totalProcess['totalHhours'];
            $production['last_process_qty'] = $lastProcess->make_qty;
            //可汇报数
            $production['allow_report_qty'] = $lastProcess->make_qty - $production['report_qty'];

            if($production['allow_report_qty'] <= 0){
                throw new \Exception('当前工单允许汇报数量为0');
            }

        }else{
            $production['total_hours']      = 0;
            $production['now_people']       = 0;
            $production['now_hours']        = 0;
            $production['last_process_qty'] = 0;
            $production['allow_report_qty'] = 0;
        }

        if($production['back_status'] != ProductionOrderBackStatus::ALREADY_BACK->value){
            //throw new \Exception('当前工单未备货完成');
        }

        return [$production];

    }

    /**
     * 回写入库数量
     * @param $reportOrderId
     * @param $materialNo
     * @param $qty
     * @return mixed
     */
    static public function rewriteInboundQty($reportOrderId,$materialNo,$qty){
        return ProductionReportDetail::where([
            ['order_id','=',$reportOrderId],
            ['material_no','=',$materialNo],
        ])->increment('inbound_qty',$qty);
    }

    /**
     * 生产汇报删除
     * @param $id
     */
    static public function deleteBy($id){

        $reportOrder = self::getReportOrderAndDetailById($id);

        if(!$reportOrder){
            throw new \Exception('汇报单不存在');
        }

        if($reportOrder->detail[0]->inbound_qty > 0){
            $wareOrder = productionWareOrderRepository::getDetailWithOrderByReportId($reportOrder->id);
            throw new \Exception("删除失败，当前汇报单已入库，入库单据：{$wareOrder->order->docno}");
        }

        //工单头
        $production = ProductionOrderRepository::getOrderById($reportOrder->production_id);

        try{

            DB::beginTransaction();

            if(!empty($production->flow_code)){
                //有工艺流程，要删除工序报工
                if($reportOrder->detail[0]->process_detail === null){
                    throw new \Exception('删除失败，请联系系统管理员处理');
                }else{
                    if(!empty($reportOrder->detail[0]->process_detail)){
                        //返还工序报工信息
                        ProcessDetailRepository::resetProcessDetailReport(explode(',',$reportOrder->detail[0]->process_detail));
                    }
                }
            }

            //删除汇报单
            ProductionReportOrder::where('id',$id)->update([
                'deletor_id' => UnitService::getUserId(),
                'deleted_at' => time()
            ]);
            //减掉工单已汇报数
            $production->decrement('report_qty',$reportOrder->detail[0]->qty);

            $kingdee = new KingDeeService();
            //反审金蝶单据
            $kingdee->form('PRD_MORPT')->unAudit($reportOrder->docno);
            //删除金蝶单据
            $kingdee->delete($reportOrder->docno);

            DB::commit();
            return true;

        }catch (\Exception $e){
            DB::rollBack();
            throw $e;
        }

    }

    /**
     * 扣减生产汇报入库数量
     * @param $reportId
     * @param $qty
     * @return mixed
     */
    static public function decInboundQtyByReportId($reportId,$qty){
        $report = self::getReportOrderAndDetailById($reportId);
        return ProductionReportDetail::where('id',$report->detail[0]->id)->decrement('inbound_qty',$qty);
    }

}
